# tests/test_api.py

import pytest
import requests
from test_data import TEST_USERS, TEST_ROLES, TEST_PERMISSIONS, TEST_USER, PASSWORD

BASE_URL = "http://localhost:5000"
USER_IDS = set()
ROLE_IDS = set()
PERMISSION_IDS = set()
USER1_ID = None
USER1_NEW_TOKEN = None


def login(username, password):
    response = requests.post(f"{BASE_URL}/auth/login", json={
        'username': username,
        'password': password
    })
    assert response.status_code == 200
    return response.json()['data']['accessToken']


def add_user(token, username, password):
    headers = {
        'Authorization': f'Bearer {token}'
    }
    response = requests.post(f"{BASE_URL}/user", json={
        'username': username,
        'password': password
    }, headers=headers)
    assert response.status_code == 200
    resp = response.json()
    data = resp.get('data')
    USER_IDS.add(data.get("id"))
    if username == "user1":
        global USER1_ID
        USER1_ID = data.get("id")
    return response.json()['data']


def add_role(token, role):
    headers = {
        'Authorization': f'Bearer {token}'
    }
    response = requests.post(f"{BASE_URL}/role", json={
        'code': role,
        'name': role
    }, headers=headers)
    assert response.status_code == 201
    resp = response.json()
    data = resp.get("data")
    ROLE_IDS.add(data.get("id"))
    return response.json()['data']


def add_permission(token, permission):
    headers = {
        'Authorization': f'Bearer {token}'
    }
    response = requests.post(f"{BASE_URL}/permission", json={
        'code': permission,
        'name': permission,
        'type': 'API'
    }, headers=headers)
    assert response.status_code == 201
    resp = response.json()
    data = resp.get("data")
    PERMISSION_IDS.add(data.get("id"))
    return response.json()['data']


def assign_permissions_to_role(token, role_id, permission_ids):
    headers = {
        'Authorization': f'Bearer {token}'
    }
    response = requests.patch(f"{BASE_URL}/role/{role_id}", json={
        'permissionIds': permission_ids
    }, headers=headers)
    assert response.status_code == 200


def delete_user(token, user_id):
    headers = {
        'Authorization': f'Bearer {token}'
    }
    response = requests.delete(f"{BASE_URL}/user/{user_id}", headers=headers)
    assert response.status_code == 200


def delete_role(token, role_id):
    headers = {
        'Authorization': f'Bearer {token}'
    }
    response = requests.delete(f"{BASE_URL}/role/{role_id}", headers=headers)
    assert response.status_code == 200


def delete_permission(token, permission_id):
    headers = {
        'Authorization': f'Bearer {token}'
    }
    response = requests.delete(f"{BASE_URL}/permission/{permission_id}", headers=headers)
    assert response.status_code == 200


@pytest.fixture(scope="module")
def admin_token():
    return login(TEST_USER, PASSWORD)


@pytest.fixture(scope="module")
def user1_token(admin_token):
    token = login(TEST_USERS['user1']['username'], TEST_USERS['user1']['password'])
    yield token


@pytest.fixture(scope="module")
def role_ids(admin_token):
    ids = list(ROLE_IDS)
    yield ids


@pytest.fixture(scope="module")
def permission_ids(admin_token):
    ids = list(PERMISSION_IDS)
    yield ids


def test_add_users(admin_token):
    for _, u in TEST_USERS.items():
        add_user(admin_token, u['username'], u['password'])


def test_login_user1(user1_token):
    assert user1_token is not None


def test_add_roles(admin_token):
    for role in TEST_ROLES:
        add_role(admin_token, role)


def test_add_permissions(admin_token):
    for permission in TEST_PERMISSIONS:
        add_permission(admin_token, permission)


def test_assign_permissions_to_role(admin_token, role_ids, permission_ids):
    assign_permissions_to_role(admin_token, role_ids[0], permission_ids)


def test_get_roles_list(admin_token):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    response = requests.get(f"{BASE_URL}/role/page", headers=headers)
    assert response.status_code == 200


def test_get_all_roles(admin_token):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    response = requests.get(f"{BASE_URL}/role", headers=headers)
    assert response.status_code == 200


def test_get_permissions_tree(admin_token):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    response = requests.get(f"{BASE_URL}/permission/tree", headers=headers)
    assert response.status_code == 200


def test_get_menu_permissions_tree(admin_token):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    response = requests.get(f"{BASE_URL}/permission/menu/tree", headers=headers)
    assert response.status_code == 200


def test_update_permission(admin_token, permission_ids):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    response = requests.patch(f"{BASE_URL}/permission/{permission_ids[2]}", json={
        'name': 'UpdatedPermission3'
    }, headers=headers)
    assert response.status_code == 200


def test_assign_roles_to_users(admin_token, role_ids):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    user_ids = list(USER_IDS)  # Assuming these are the user IDs for User1, User2, User3
    for role_id in role_ids[:2]:  # Role1 and Role2
        response = requests.patch(f"{BASE_URL}/role/users/add/{role_id}", json={
            'userIds': user_ids
        }, headers=headers)
        assert response.status_code == 200


def test_get_users_list(admin_token):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    response = requests.get(f"{BASE_URL}/user", headers=headers)
    assert response.status_code == 200


def test_user1_get_details(user1_token):
    headers = {
        'Authorization': f'Bearer {user1_token}'
    }
    response = requests.get(f"{BASE_URL}/user/detail", headers=headers)
    assert response.status_code == 200


def test_reset_user1_password(admin_token):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }

    response = requests.patch(f"{BASE_URL}/user/password/reset/{USER1_ID}", json={
        'password': 'newuser1pass'
    }, headers=headers)
    assert response.status_code == 200


def test_user1_login_with_new_password():
    token = login(TEST_USERS['user1']['username'], 'newuser1pass')
    assert token is not None


def test_user1_get_details_with_new_token():
    global USER1_NEW_TOKEN
    USER1_NEW_TOKEN = login(TEST_USERS['user1']['username'], 'newuser1pass')
    headers = {
        'Authorization': f'Bearer {USER1_NEW_TOKEN}'
    }
    response = requests.get(f"{BASE_URL}/user/detail", headers=headers)
    assert response.status_code == 200


def test_user1_logout(user1_token):
    headers = {
        'Authorization': f'Bearer {USER1_NEW_TOKEN}'
    }
    response = requests.post(f"{BASE_URL}/auth/logout", headers=headers)
    assert response.status_code == 200


def test_remove_permissions_from_role(admin_token, role_ids, permission_ids):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    response = requests.patch(f"{BASE_URL}/role/{role_ids[0]}", json={
        'permissionIds': []
    }, headers=headers)
    assert response.status_code == 200


def test_remove_roles_from_users(admin_token, role_ids):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    user_ids = list(USER_IDS)  # Assuming these are the user IDs for User1, User2, User3
    for role_id in role_ids[:2]:  # Role1 and Role2
        response = requests.patch(f"{BASE_URL}/role/users/remove/{role_id}", json={
            'userIds': user_ids
        }, headers=headers)
        assert response.status_code == 200


def test_delete_permissions(admin_token, permission_ids):
    for permission_id in permission_ids:
        delete_permission(admin_token, permission_id)


def test_delete_roles(admin_token, role_ids):
    for role_id in role_ids:
        delete_role(admin_token, role_id)


def test_delete_users(admin_token):
    user_ids = list(USER_IDS)  # Assuming these are the user IDs for User1, User2, User3
    for user_id in user_ids:
        delete_user(admin_token, user_id)


def test_final_admin_logout(admin_token):
    headers = {
        'Authorization': f'Bearer {admin_token}'
    }
    response = requests.post(f"{BASE_URL}/auth/logout", headers=headers)
    assert response.status_code == 200
